package hldh.push

import java.security.MessageDigest
import java.util

import scala.collection.mutable.ArrayBuffer

/**
 * Created by jf on 16/1/24.
 */
class ConsistencyHash[T] {


  val shards = ArrayBuffer[T]()

  val nodes = new util.TreeMap[Long, T]()

  val VIRTUAL_NUM = 4

  def add(node: T): Unit = {
    shards += node
    for (i <- 0 until VIRTUAL_NUM) {
      nodes.put(hash(md5("SHARD-" + node + "-NODE-" + i), i), node)
    }

  }

  def remove(node: T): Unit = {
    shards -= node
    for (i <- 0 until VIRTUAL_NUM) {
      nodes.remove(hash(md5("SHARD-" + node + "-NODE-" + i), i))
    }
  }

  def get(k: Any): T = {
    val key = hash(md5(k.toString), VIRTUAL_NUM - 1)
    val tailMap = nodes.tailMap(key)
    val _key = if (tailMap.isEmpty) nodes.firstKey else tailMap.firstKey
    nodes.get(_key)
  }

  def hash(digest: Array[Byte], nTime: Int): Long = {
    val rv = Long.box((digest.apply(3 + nTime * 4) & 0xFF) << 24) | Long.box((digest.apply(2 + nTime * 4) & 0xFF) << 16) | Long.box((digest.apply(1 + nTime * 4) & 0xFF) << 8) | (digest.apply(0 + nTime * 4) & 0xFF)
    rv & 0xffffffffL
  }

  def md5(s: String): Array[Byte] = {
    MessageDigest.getInstance("MD5").digest(s.getBytes)
  }

  def print() = println(nodes)

}

object ConsistencyHash extends App {
  val c = new ConsistencyHash[String]()

  c.add("127.0.0.1:2551")
  c.add("127.0.0.1:2552")
  c.add("127.0.0.1:2553")
  c.add("127.0.0.1:2554")

  c.print()

  var nodes = new util.HashMap[String, util.List[Int]]()
  val t = System.nanoTime()
  for (i <- 0 until 100000) {
    val n = c.get(i)
//    println(n -> i)
  }

  println((System.nanoTime() - t) / 100000)

  println(nodes)
}